package com.zenika.zenbinding.sample.client;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ChangeListener;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.zenika.zenbinding.client.ZenBinder;
import com.zenika.zenbinding.client.converter.EnumConverter;
import com.zenika.zenbinding.client.converter.Radio2BooleanConverter;
import com.zenika.zenbinding.client.exception.DataMessage;
import com.zenika.zenbinding.client.feedback.EnumFeedbackManager;
import com.zenika.zenbinding.client.feedback.FeedbackManager;
import com.zenika.zenbinding.client.feedback.StyleFeedbackManager;
import com.zenika.zenbinding.client.handler.ListBindingHandler;
import com.zenika.zenbinding.client.model.ValueModel;
import com.zenika.zenbinding.client.validator.RangeValidator;
import com.zenika.zenbinding.client.validator.ValidationContext;
import com.zenika.zenbinding.client.validator.Validators;
import com.zenika.zenbinding.client.widget.RadioGroup;
import com.zenika.zenbinding.sample.model.Category;
import com.zenika.zenbinding.sample.model.Dialect;
import com.zenika.zenbinding.sample.model.Language;
import com.zenika.zenbinding.sample.model.LevelEnum;
import com.zenika.zenbinding.sample.model.Person;

public class FormulairePanel extends VerticalPanel implements ClickListener {

	private ValidationContext validationContext;
	private Person person;
	private List languages;
	private List dialects;
	private Grid grid;

	public FormulairePanel() {
		// init BusinessObject(s)
		this.setUp();
		this.validationContext = new ValidationContext();

		grid = new Grid(12, 3);
		FeedbackManager styleFeedback = new StyleFeedbackManager();
		FeedbackManager enumFeedback = new EnumFeedbackManager("error");

		Label nomLbl = new Label("Nom : ");
		grid.setWidget(0, 0, nomLbl);
		TextBox nomTb = new TextBox();
		grid.setWidget(0, 1, nomTb);
		ValueModel nomMdl = ZenBinder.bindValue(nomTb, this.person, "name");
		nomMdl.addValidator(this.validationContext, Validators.REQUIRED);
		nomMdl.setFeedbackManager(enumFeedback, "nom");
		Label requis = new Label("champ requis");
		requis.setStyleName("restriction");
		grid.setWidget(0, 2, requis);

		Label prenomLbl = new Label("Prénom : ");
		grid.setWidget(1, 0, prenomLbl);
		TextBox prenomTb = new TextBox();
		ZenBinder.bindValue(prenomTb, this.person, "firstName");
		ValueModel prenomMdl = ZenBinder.bindValue(prenomTb, this.person, "firstName");
		prenomMdl.addValidator(this.validationContext, Validators.REQUIRED);
		prenomMdl.setFeedbackManager(enumFeedback, "prenom");
		grid.setWidget(1, 1, prenomTb);
		Label requis2 = new Label("champ requis");
		requis2.setStyleName("restriction");
		grid.setWidget(1, 2, requis2);

		Label ageLbl = new Label("Age : ");
		grid.setWidget(2, 0, ageLbl);
		TextBox ageTb = new TextBox();
		grid.setWidget(2, 1, ageTb);
		ValueModel ageMdl = ZenBinder.bindValue(ageTb, this.person, "age");
		ageMdl.addValidator(this.validationContext, new RangeValidator("18", "65"));
		ageMdl.setFeedbackManager(styleFeedback);
		Label trancheAge = new Label("entre 18 et 65 ans");
		trancheAge.setStyleName("restriction");
		grid.setWidget(2, 2, trancheAge);

		Label celibLbl = new Label("Célibataire : ");
		grid.setWidget(3, 0, celibLbl);
		CheckBox celibCb = new CheckBox();
		ZenBinder.bindValue(celibCb, this.person, "bachelor");
		grid.setWidget(3, 1, celibCb);

		Label sexeLbl = new Label("Sexe :");
		grid.setWidget(4, 0, sexeLbl);
		RadioGroup sexeLst = new RadioGroup("sexe");
		String[] sexes = { "Homme", "Femme" };
		ListBindingHandler sexeHandler = ZenBinder.createListBindingHandler(sexeLst, sexes);
		ZenBinder.bindList(sexeHandler, this.person, "sex");
		grid.setWidget(4, 1, sexeLst);

		Label annivLbl = new Label("Date de naissance : ");
		grid.setWidget(5, 0, annivLbl);
		TextBox annivTb = new TextBox();
		ValueModel bdayModel = ZenBinder.bindValue(annivTb, this.person, "birthday");
		bdayModel.setFeedbackManager(styleFeedback);
		grid.setWidget(5, 1, annivTb);
		Label formatDate = new Label("JJ/MM/AAAA");
		formatDate.setStyleName("restriction");
		grid.setWidget(5, 2, formatDate);

		Label catLbl = new Label("Catégories : ");
		grid.setWidget(6, 0, catLbl);
		ListBox catLb = new ListBox();
		ArrayList categories = new ArrayList();
		categories.add(new Category("Technicien"));
		categories.add(new Category("Ingénieur"));
		categories.add(new Category("Cadre"));
		categories.add(new Category("Cadre Sup"));
		ListBindingHandler handler = ZenBinder.createListBindingHandler(catLb, categories, "name");
		ZenBinder.bindList(handler, this.person, "category");
		grid.setWidget(6, 1, catLb);

		Label test5Lbl = new Label("Occupation :");
		grid.setWidget(7, 0, test5Lbl);
		RadioGroup occupationLst = new RadioGroup("occupation");
		String[] occupations = { "Etudiant(e)", "Employé(e)" };
		ListBindingHandler occupationHandler = ZenBinder.createListBindingHandler(occupationLst, occupations);
		ZenBinder.bindList(occupationHandler, this.person, "occupation", new Radio2BooleanConverter(occupations));
		grid.setWidget(7, 1, occupationLst);

		Label langLbl = new Label("Languages : ");
		grid.setWidget(8, 0, langLbl);
		ListBox langLb = new ListBox();
		langLb.addChangeListener(new ChangeLanguageListener());
		ListBindingHandler langHandler = ZenBinder.createListBindingHandler(langLb, this.languages, "name");
		ZenBinder.bindList(langHandler, this.person, "language");
		grid.setWidget(8, 1, langLb);

		Label dialectLbl = new Label("Dialects : ");
		grid.setWidget(9, 0, dialectLbl);
		ListBox dialectLb = new ListBox();
		ListBindingHandler dialectHandler = ZenBinder.createListBindingHandler(dialectLb, new ArrayList(), "name");
		ZenBinder.bindList(dialectHandler, this.person, "dialect");
		grid.setWidget(9, 1, dialectLb);

		Label levelLbl = new Label("Level : ");
		grid.setWidget(10, 0, levelLbl);
		ListBox levelLb = new ListBox();
		ListBindingHandler levelHandler = ZenBinder.createListBindingHandler(levelLb, LevelEnum.getLevels());
		ZenBinder.bindList(levelHandler, this.person, "level", new EnumConverter(LevelEnum.getLevels()));
		grid.setWidget(10, 1, levelLb);

		Button bouton = new Button("Afficher");
		bouton.addClickListener(this);
		grid.setWidget(11, 1, bouton);

		this.add(grid);
	}

	public void onClick(Widget sender) {
		Window.alert(this.person.toString());

		Set errorMessages = this.validationContext.validate();
		if (!errorMessages.isEmpty()) {
			String errorDisplay = "";
			Iterator errorMessagesIter = errorMessages.iterator();
			while (errorMessagesIter.hasNext()) {
				DataMessage currMessage = (DataMessage) errorMessagesIter.next();
				errorDisplay += currMessage.getMessage();
			}

			Window.alert(errorDisplay);
		}
	}

	private void updateDialectsList(Language languageSelected) {
		// get the dialect ListBox widget from he grid
		ListBox listBox = (ListBox) this.grid.getWidget(9, 1);

		// clear this ListBox, in case some values are already filled in
		listBox.clear();

		// List containing all the Dialect BusinessObject with a languageId
		// equals to the languageSelected.getId()
		// selected
		List dialectsByLanguage = new ArrayList();
		dialectsByLanguage.add(new Dialect(-1, "Please select a dialect", languageSelected.getId()));

		// fill dialectsByLanguage with the relevant Dialect BusinessObject
		for (int i = 0; i < this.dialects.size(); i++) {
			Dialect currentDialect = (Dialect) this.dialects.get(i);
			if (currentDialect.getLanguageId() == languageSelected.getId())
				dialectsByLanguage.add(currentDialect);
		}

		// rebind ListBox with new set of values
		ZenBinder.bindListBox(listBox, this.person, "dialect", dialectsByLanguage, "name");
	}

	public class ChangeLanguageListener implements ChangeListener {
		public void onChange(Widget sender) {
			ListBox languages = (ListBox) sender;
			int selectedIndex = languages.getSelectedIndex();
			Language languageSelected = (Language) FormulairePanel.this.languages.get(selectedIndex);
			FormulairePanel.this.updateDialectsList(languageSelected);
		}
	}

	private void setUp() {
		this.languages = new ArrayList();
		this.languages.add(new Language(-1, "Please select a language"));
		this.languages.add(new Language(1, "Français"));
		this.languages.add(new Language(2, "Chinois"));

		this.dialects = new ArrayList();
		this.dialects.add(new Dialect(1, "Cantonais", 2));
		this.dialects.add(new Dialect(2, "Alsacien", 1));
		this.dialects.add(new Dialect(3, "Mandarin", 2));
		this.dialects.add(new Dialect(4, "Breton", 1));
		this.dialects.add(new Dialect(5, "Parisien", 1));

		this.person = new Person("Durand", "Jean-Pierre");
		this.person.setAge(32);
		// l'énumération des mois commence à 0 !
		this.person.setBirthday(new Date(1983, 11, 31));
		this.person.setCategory(new Category("Ingénieur"));
		this.person.setSex("Femme");
		this.person.setOccupation(new Boolean(false));
		this.person.setLevel((Long) LevelEnum.MID_LEVEL.getKey());
	}

}
